package com.dhsc.util;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;

import org.apache.commons.codec.binary.Base64;

import com.dhsc.domain.yypt.DynRSAVo;

/**
 * @ClassName:  RSAEncrypt
 * @Description: rsa加密解密
 * @date:   2020年7月3日 上午10:17:09       
 * @author: chenlong
 * @Copyright:  迅优智超
 */
public class DynRSAEncrypt {
	
	private DynRSAEncrypt()
	{

	}
	
	public static void main(String[] args) throws Exception {
	
		/*DynRSAVo d = genKeyPair(1);
		String message = "http://tyxxpt.longone.com.cn/zuul/wwtapp/";
		
		String messageEn = encrypt(d, message, 1);
		System.out.println("加密后的字符串为:" + messageEn);
		String messageDe = decrypt(d, messageEn, 1);
		System.out.println("还原后的字符串为:" + messageDe);*/
		
	}

	/** 
	 * 随机生成密钥对 
	 * type  1.前    2.后
	 * @throws NoSuchAlgorithmException 
	 */  
	public static DynRSAVo genKeyPair(int type) throws NoSuchAlgorithmException {  
		// KeyPairGenerator类用于生成公钥和私钥对，基于RSA算法生成对象  
		KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA");  
		// 初始化密钥对生成器，密钥大小为96-1024位  
		keyPairGen.initialize(2048,new SecureRandom());  
		// 生成一个密钥对，保存在keyPair中  
		KeyPair keyPair = keyPairGen.generateKeyPair();  
		RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();   // 得到私钥  
		RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();  // 得到公钥  
		String publicKeyString = new String(Base64.encodeBase64(publicKey.getEncoded()));  
		// 得到私钥字符串  
		String privateKeyString = new String(Base64.encodeBase64((privateKey.getEncoded())));  
		// 将公钥和私钥保存到Map
		
		DynRSAVo d = new DynRSAVo();
		if(type == 1)
		{
			d.setFront_publicKey(publicKeyString);
			d.setFront_privateKey(privateKeyString);
		}else{
			d.setAfter_publicKey(publicKeyString);
			d.setAfter_privateKey(privateKeyString);
		}
		return d;
	}  
	/** 
	 * RSA公钥加密 
	 *  
	 * @param str 
	 *            加密字符串
	 * @param publicKey 
	 *            公钥 
	 * @return 密文 
	 * @throws NoSuchAlgorithmException 
	 * @throws InvalidKeySpecException 
	 * @throws NoSuchPaddingException 
	 * @throws InvalidKeyException 
	 * @throws BadPaddingException 
	 * @throws IllegalBlockSizeException 
	 * @throws IOException 
	 * @throws Exception 
	 *             加密过程中的异常信息 
	 */  
	public static String encrypt(DynRSAVo d, String str, int type) throws NoSuchAlgorithmException, InvalidKeySpecException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException, IOException{
		if(str == null)
		{
			str = "";
		}
		//获取redis中存储的动态RSA
		String publicKey = "";
		if(type == 1)
		{
			publicKey = d.getFront_publicKey();
		}else if(type == 2)
		{
			publicKey = d.getAfter_publicKey();
		}
		byte[] decodePublicKeyByte = Base64.decodeBase64(publicKey);
        //调用X509EncodedKeySpec对象,转换格式
        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(decodePublicKeyByte);
        //调用密钥工厂
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        PublicKey publick = keyFactory.generatePublic(keySpec);

        //调用Java加密的Cipher对象，
        Cipher cipher = Cipher.getInstance("RSA");
        cipher.init(Cipher.ENCRYPT_MODE,publick);//第一个参数表示这是加密模式，第二个参数表示密钥

        //分段加密
        byte[] bytesContent = str.getBytes(StandardCharsets.UTF_8);
        int inputLen = bytesContent.length;
        int offLen = 0;//偏移量
        int i = 0;
        ByteArrayOutputStream bops = new ByteArrayOutputStream();
        while(inputLen - offLen > 0){
            byte [] cache;
            if(inputLen - offLen > 245){
                cache = cipher.doFinal(bytesContent, offLen,245);
            }else{
                cache = cipher.doFinal(bytesContent, offLen,inputLen - offLen);
            }
            bops.write(cache);
            i++;
            offLen = 245 * i;
        }
        bops.close();
        byte[] encryptedData = bops.toByteArray();
        //使用Base64对加密结果进行编码
        return Base64.encodeBase64String(encryptedData);
	}

	/** 
	 * RSA私钥解密
	 *  
	 * @param str 
	 *            加密字符串
	 * @param privateKey 
	 *            私钥 
	 * @return 铭文
	 * @throws NoSuchAlgorithmException 
	 * @throws InvalidKeySpecException 
	 * @throws NoSuchPaddingException 
	 * @throws InvalidKeyException 
	 * @throws BadPaddingException 
	 * @throws IllegalBlockSizeException 
	 * @throws IOException 
	 * @throws Exception 
	 *             解密过程中的异常信息 
	 */  
	public static String decrypt(DynRSAVo d, String str, int type) throws NoSuchAlgorithmException, InvalidKeySpecException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException, IOException{
		if(str == null)
		{
			str = "";
		}
		String privateKey = "";
		if(type == 1)
		{
			privateKey = d.getFront_privateKey();
		}else if(type == 2)
		{
			privateKey = d.getAfter_privateKey();
		}
		byte[] decodePrivateKeyByte = Base64.decodeBase64(privateKey);
        //调用PKCS8EncodedKeySpec对象
        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(decodePrivateKeyByte);
        //调用密钥工厂
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        PrivateKey privatek = keyFactory.generatePrivate(keySpec);
        //调用Java加密的Cipher对象，
        Cipher cipher = Cipher.getInstance("RSA");
        cipher.init(Cipher.DECRYPT_MODE,privatek);//第一个参数表示这是加密模式，第二个参数表示密钥

        byte[] bytesContent = Base64.decodeBase64(str.getBytes(StandardCharsets.UTF_8));
        int inputLen = bytesContent.length;
        int offLen = 0;
        int i = 0;
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        while(inputLen - offLen > 0){
            byte[] cache;
            if(inputLen - offLen > 256){
                cache = cipher.doFinal(bytesContent,offLen,256);
            }else{
                cache = cipher.doFinal(bytesContent,offLen,inputLen - offLen);
            }
            byteArrayOutputStream.write(cache);
            i++;
            offLen = 256 * i;
        }
        byteArrayOutputStream.close();
        byte[] byteArray = byteArrayOutputStream.toByteArray();

        //使用Base64对加密结果进行编码
        return URLDecoder.decode(new String(byteArray),"UTF-8");
	}

}
